﻿using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using Core;
using Core.Domain.Entities;
using Core.Domain.Enums;

namespace TallyJ.FrontDesk
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class FrontDeskWindow : IFrontDeskView
  {
    public static RoutedCommand SaveMethodCommand = new RoutedCommand();
    private Voter _currentVoter;
    private FrontDeskPresenter _FrontDeskPresenter;
    private InputMode _inputMode = InputMode.SearchInList;

    ///<summary></summary>
    public FrontDeskWindow()
    {
      InitializeComponent();

      lbBallotSubmissionMethod.ItemsSource = EnumGeneric<BallotSubmissionMethod>.Items;

      SwitchMode(InputMode.SearchInList, false);
    }

    #region IFrontDeskView Members

    public FrontDeskDataContext LocalDataContext
    {
      set { DataContext = value; }
    }

    ///<summary></summary>
    public FrontDeskPresenter Presenter
    {
      set
      {
        _FrontDeskPresenter = value;
        //_FrontDeskPresenter.DoAnimation += OnAnimate;
        MouseWheel += _FrontDeskPresenter.OnMouseWheel;

        Matching = new ObservableCollection<Person>();
        txtInput.TextChanged += _FrontDeskPresenter.InputChanged;

        lbFoundMatchingNames.SourceUpdated += LbMatchingOnSourceUpdated;
        lbFoundMatchingNames.MouseDoubleClick += LbFoundMatchingNamesOnMouseDoubleClick;

        CommandBindings.Add(new CommandBinding(SaveMethodCommand, SaveMethodChoice, CanSaveMethod));
        btnSaveMethod.Command = SaveMethodCommand;
      }
    }

    public string InputText
    {
      get { return txtInput.Text; }
      set { txtInput.Text = value; }
    }

    public ObservableCollection<Person> Matching { get; set; }

    ///<summary>Expose the dispatcher to presenters</summary>
    ///<param name="action"></param>
    public void ViewDispatcherAction(Action action)
    {
      this.DispatcherAction(action);
    }

    #endregion

    private void CanSaveMethod(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = true;
    }

    private void SaveMethodChoice(object sender, ExecutedRoutedEventArgs e)
    {
      var resultItem = (ResultItem) lbFoundMatchingNames.SelectedItem;

      _FrontDeskPresenter.SaveVote(resultItem.Voter, (BallotSubmissionMethod) lbBallotSubmissionMethod.SelectedItem);

      SwitchMode(InputMode.SearchInList, true);
    }

    private void LbFoundMatchingNamesOnMouseDoubleClick(object sender, MouseButtonEventArgs args)
    {
      SwitchMode(InputMode.RecordMethod, true);
    }

    private void LbMatchingOnSourceUpdated(object sender, DataTransferEventArgs args)
    {
      lbFoundMatchingNames.SelectedIndex = 0;
    }

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
      base.OnPreviewKeyDown(e);


      switch (_inputMode)
      {
        case InputMode.SearchInList:
          var currentIndex = lbFoundMatchingNames.SelectedIndex;
          switch (e.Key)
          {
            case Key.Up:
              lbFoundMatchingNames.SelectedIndex = currentIndex - (currentIndex > 0 ? 1 : 0);
              lbFoundMatchingNames.ScrollIntoView(lbFoundMatchingNames.SelectedItem);
              e.Handled = true;
              break;

            case Key.Down:
              lbFoundMatchingNames.SelectedIndex = currentIndex
                                                   + (currentIndex < lbFoundMatchingNames.Items.Count ? 1 : 0);
              lbFoundMatchingNames.ScrollIntoView(lbFoundMatchingNames.SelectedItem);
              e.Handled = true;
              break;
            
            case Key.Tab:
              e.Handled = true; // swallow the tab key!
              break;
            
            case Key.Enter:
              if (currentIndex != -1)
              {
                SwitchMode(InputMode.RecordMethod, true);
                e.Handled = true;
              }
              break;

            case Key.Escape:
              if (txtInput.Text.HasContent())
              {
                txtInput.Text = string.Empty;
              }
              else
              {
                Close();
              }
              e.Handled = true;
              break;
          }
          break;


        case InputMode.RecordMethod:

          switch (e.Key)
          {
            case Key.Up:
              currentIndex = lbBallotSubmissionMethod.SelectedIndex;
              lbBallotSubmissionMethod.SelectedIndex = currentIndex - (currentIndex > 0 ? 1 : 0);
              e.Handled = true;
              break;

            case Key.Down:
              currentIndex = lbBallotSubmissionMethod.SelectedIndex;
              lbBallotSubmissionMethod.SelectedIndex = currentIndex
                                                       + (currentIndex < lbBallotSubmissionMethod.Items.Count ? 1 : 0);
              e.Handled = true;
              break;

            case Key.Enter:
              var resultItem = (ResultItem) lbFoundMatchingNames.SelectedItem;

              _FrontDeskPresenter.SaveVote(resultItem.Voter,
                                           (BallotSubmissionMethod) lbBallotSubmissionMethod.SelectedItem);

              SwitchMode(InputMode.SearchInList, true);

              e.Handled = true;
              break;

            case Key.Escape:
              SwitchMode(InputMode.SearchInList, false);

              e.Handled = true;
              break;
          }

          break;
        default:
          throw new ArgumentOutOfRangeException();
      }
    }

    private void SwitchMode(InputMode newMode, bool pressedEnter)
    {
      _inputMode = newMode;

      switch (newMode)
      {
        case InputMode.SearchInList:

          if (pressedEnter)
          {
            // refresh list
            _FrontDeskPresenter.InputChanged(null, null);
          }

          MethodSelectionPanel.Visibility = Visibility.Hidden;

          lbFoundMatchingNames.IsEnabled =
                txtInput.IsEnabled = true;

          txtInput.SelectAll();
          txtInput.Focus();

          break;


        case InputMode.RecordMethod:

          var resultItem = (ResultItem) lbFoundMatchingNames.SelectedItem;

          lblCurrentPersonName.Text = resultItem.DisplayMain;
          lbBallotSubmissionMethod.SelectedItem = resultItem.Voter.BallotSubmissionMethod;

          MethodSelectionPanel.Visibility = Visibility.Visible;

          lbBallotSubmissionMethod.Focus();

          lbFoundMatchingNames.IsEnabled =
                txtInput.IsEnabled = false;

          break;

        default:
          throw new ArgumentOutOfRangeException("mode");
      }
    }

    #region Nested type: InputMode

    private enum InputMode
    {
      SearchInList,
      RecordMethod
    }

    #endregion

    ///<summary>Does animation</summary>
    ///<param name="sender"></param>
    ///<param name="args"></param>
    //public void OnAnimate(object sender, AnimateTypeArg args)
    //{
    //  try
    //  {
    //    var storyboard = (Storyboard) Resources[args.AnimationName];
    //    storyboard.Begin(border, HandoffBehavior.Compose);
    //  }
    //  catch (Exception e)
    //  {
    //    MessageBox.Show(e.AllMessages());
    //  }
    //}

    /* 
    private void SetupCornerDisplay()
    {
      // show now
      ClockTimerOnElapsed(null, null);

      _clockTimer = new Timer
                      {
                            Interval = 1000
                      };
      _clockTimer.Elapsed += ClockTimerOnElapsed;
      _clockTimer.Start();
      // not working??
    }

    private void ClockTimerOnElapsed(object sender, ElapsedEventArgs args)
    {
      tbClockDisplay.DispatcherAction(delegate { tbClockDisplay.Text = DateTime.Now.ToString("h:mm:ss tt"); });
    }
*/
  }
}